package com.pro.service;

import com.alibaba.fastjson.JSONObject;
import com.pro.constant.RegisterConstant;
import com.pro.model.ServiceInstance;
import com.pro.parameter.ReqInfoDto;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Copyright C 四川众鹏科技有限公司
 * All right reserved.  RegisterServices
 * 创建者：aoneng 2022/9/16
 * Description:
 * 备注   :
 * version:  V1.0
 * <author> - <version > - <time>  -    <desc>
 *
 * @author 敖能         V1.0       2022/9/16    完成基本功能
 */
@Service
public class RegisterServices {
    private static final Log log = LogFactory.getLog(RegisterServices.class);
    private ScheduledExecutorService scheduledService = Executors.newSingleThreadScheduledExecutor();
    public RegisterServices(){
        // 服务注册中心每隔3s 检查地址是否宕机
        scheduledService.scheduleAtFixedRate(new ServerHalt(), 3, 3, TimeUnit.SECONDS);
    }
    /**
     * juc知识整合
     * set底层如何实现？ HashMap集合
     * HashSet--无序
     * HashSet--  192.168.110.2 192.168.110.1
     */
    private static volatile Map<String, HashSet<ServiceInstance>> mapServiceInstances = new ConcurrentHashMap<>();

    public boolean put(ReqInfoDto reqInfo){
        //1.先判断容器 是否已经注册该服务
        String serviceName = reqInfo.getServiceName();
        HashSet<ServiceInstance> serviceInstances = mapServiceInstances.get(serviceName);
        if(serviceInstances==null){//注册
            serviceInstances=new HashSet<>();
            mapServiceInstances.put(serviceName, serviceInstances);
        }
        // 将接口地址存放到 服务注册中心中
        ServiceInstance serviceInstance = new ServiceInstance(serviceName, reqInfo.getServiceAddres(), System.currentTimeMillis());
       try {
           serviceInstances.add(serviceInstance);
           return true;
       }catch (Exception ex){
           return  false;
       }
    }

    /**
     * 服务续约
     *
     * @param reqInfo
     * @return
     */
    public boolean renewal(ReqInfoDto reqInfo) {
        ServiceInstance serviceInstance = findByServiceInstance(reqInfo);
        if (serviceInstance == null) {
            // 在做服务续约时 发现 在容器中没有该服务，可能是上一次将服务剔除了,也可能是服务端重启了，需要将所有服务添加进来
            return put(reqInfo);
        }
        // 用当前时间+5000毫秒，不能用上次续约时间，可能存在上次掉了，后面续约时间都偏差
        serviceInstance.setLastRenewalTime( System.currentTimeMillis()+ reqInfo.getRenewalDuration());
        log.info("续约成功...");
        return true;
    }
    private ServiceInstance findByServiceInstance(ReqInfoDto reqInfo, boolean isDelete) {
        String serviceAddres = reqInfo.getServiceAddres();
        if (StringUtils.isEmpty(serviceAddres)) {
            return null;
        }
        // 根据服务的名称 查找 对应 注册 多个接口地址
        HashSet<ServiceInstance> serviceInstances = mapServiceInstances.get(reqInfo.getServiceName());
        if (serviceInstances == null) {
            //没有找到服务列表
            log.error("<Service list not found>");
            return null;
        }
        // 循环遍历根据服务名称+服务地址 查找该对象
        for (ServiceInstance serviceInstance : serviceInstances) {
            if (serviceInstance.getServiceAddres().equals(serviceAddres)) {
                if (isDelete) {
                    serviceInstances.remove(serviceInstance);
                }
                return serviceInstance;
            }
        }
        return null;
    }

    private ServiceInstance findByServiceInstance(ReqInfoDto reqInfo) {
        return findByServiceInstance(reqInfo, false);
    }

    class ServerHalt implements  Runnable{
        @Override
        public void run() {
            mapServiceInstances.forEach((serviceName,serviceList)->{
                serviceList.forEach(serviceInstance->{
                    //当前时间-续约时长大于最后续约时间，证明已经过期了，将服务下限
                    if(System.currentTimeMillis()- RegisterConstant.DELETEIP_TIMEOUT>serviceInstance.getLastRenewalTime()){
                        log.info("服务名称：" + serviceInstance.getServiceName() + "," +
                                "服务地址" + serviceInstance.getServiceAddres() + ",当前系统时间:" + System.currentTimeMillis()
                                + ",该服务上一次续约时间" + serviceInstance.getLastRenewalTime() + "服务被剔除.");
                        serviceList.remove(serviceInstance);
                    }
                });
            });
            log.info("当前所有服务"+ JSONObject.toJSONString(mapServiceInstances));
        }
    }
}
